package com.zhejiangzhengyuan.municipal_common.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhejiangzhengyuan.municipal_common.entity.Device;
import com.zhejiangzhengyuan.municipal_common.entity.UserInfo;
import com.zhejiangzhengyuan.municipal_common.entity.WarnEvent;
import com.zhejiangzhengyuan.municipal_common.entity.WarnMessage;
import com.zhejiangzhengyuan.municipal_common.entity.vo.WarnEventChartVo;
import com.zhejiangzhengyuan.municipal_common.mapper.DeviceMapper;
import com.zhejiangzhengyuan.municipal_common.mapper.UserInfoMapper;
import com.zhejiangzhengyuan.municipal_common.mapper.WarnEventMapper;
import com.zhejiangzhengyuan.municipal_common.response.ResponseVo;
import com.zhejiangzhengyuan.municipal_common.service.WarnEventService;
import com.zhejiangzhengyuan.municipal_common.service.WarnMessageService;
import com.zhejiangzhengyuan.municipal_common.utils.ConstantUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.zhejiangzhengyuan.municipal_common.utils.DateFormatUtil.*;

/**
 * 警报事件表，存储物联网或人工上报的警报事件数据 服务实现类
 *
 * @author linju
 * @since 2019-11-22
 */
@Service
public class WarnEventServiceImpl extends ServiceImpl<WarnEventMapper, WarnEvent>
    implements WarnEventService {
  @Autowired private WarnEventMapper warnEventMapper;
  @Autowired private WarnMessageService warnMessageService;
  @Autowired private DeviceMapper deviceMapper;
  @Autowired private UserInfoMapper userInfoMapper;

  private String dayPattern = "yyyy-MM-dd";

  private String[] dataOrigin =
      new String[] {
        ConstantUtil.WARN_DATA_ORIGIN.SYSTEM,
        ConstantUtil.WARN_DATA_ORIGIN.MOBILE,
        ConstantUtil.WARN_DATA_ORIGIN.PC
      };

  @Override
  public ResponseVo warnEventChart(String startTime, String endTime) {
    try {
      // 获取起始时间timestamp
      long startTimestamp = getTimeByString(dayPattern, startTime);
      long endTimestamp = getTimeByString(dayPattern, endTime);
      // 若时间小于等于3天 时间粒度为小时，否则按日返回;计算日期间隔 需+1
      int timeInterval = (int) ((endTimestamp - startTimestamp) / (24 * 60 * 60 * 1000) + 1);
      if (timeInterval > 3) {
        return ResponseVo.successWithData(getChartVoByDay(startTimestamp, timeInterval));
      } else {
        return ResponseVo.successWithData(getChartVoByHours(startTimestamp, timeInterval));
      }
    } catch (ParseException e) {
      e.printStackTrace();
      return new ResponseVo(ConstantUtil.HTTP_CODE.CLIENT_PARAM_ERROR, "请提供标准日期，格式为 年-月-日");
    }
  }
  // 根据天返回数据
  private List<WarnEventChartVo> getChartVoByDay(long startTimestamp, int timeInterval) {
    // 获取格式化的开始时间
    Calendar date = calendarFormat(startTimestamp);
    List<WarnEventChartVo> results = new ArrayList<>();
    long startStamp;
    //    long endStamp = 0;
    //    WarnEventChartVo warnEventChartVo;
    for (int i = 0; i < timeInterval; i++) {
      // 获取起始时间
      startStamp = date.getTimeInMillis();
      // 获取后一天的起始时间减一 为当天的结束时间
      date.add(Calendar.DATE, 1);
      results.add(formatChartVo(dayPattern, startStamp, date));
    }
    return results;
  }

  // 根据小时返回数据
  private List<WarnEventChartVo> getChartVoByHours(long startTimestamp, int timeInterval) {
    // 获取格式化的开始时间
    Calendar date = calendarFormat(startTimestamp);
    List<WarnEventChartVo> results = new ArrayList<>();
    long startStamp;
    //    WarnEventChartVo warnEventChartVo;
    for (int i = 0; i < timeInterval; i++) {
      // 一天内for24次 取每天24小时的数据
      for (int j = 0; j < 24; j++) {
        // 获取起始时间
        startStamp = date.getTimeInMillis();
        // 封装每个小时的返回值
        date.add(Calendar.HOUR_OF_DAY, 1);
        String hourPattern = "yyyy-MM-dd HH:mm:ss";
        results.add(formatChartVo(hourPattern, startStamp, date));
      }
    }
    return results;
  }

  private WarnEventChartVo formatChartVo(String pattern, long startStamp, Calendar date) {
    // 区分开 并不是返回time的格式，该格式供pgSql匹配timestamp使用
    String hourPattern = "yyyy-MM-dd HH:mm:ss";
    long endStamp = date.getTimeInMillis() - 1;
    WarnEventChartVo warnEventChartVo = new WarnEventChartVo();
    warnEventChartVo.setTime(getStringByTime(pattern, startStamp));
    // 获得data数据
    for (String origin : dataOrigin) {
      warnEventChartVo.addCounts(
          origin,
          warnEventMapper.selectChartVoByTimestampAndOrigin(
              getStringByTime(hourPattern, startStamp),
              getStringByTime(hourPattern, endStamp),
              origin));
    }
    return warnEventChartVo;
  }

  // 井盖、雨污混排、道路积水警告事件复位
  @Override
  @Transactional(rollbackFor = Exception.class)
  public int updateWarnEvent(WarnEvent warnEvent) {
    // 若deviceId为1则不处理device
    if (warnEvent.getDeviceId() != 1L) {
      Device device = new Device();
      device.setId(warnEvent.getDeviceId());
      device.setWarn(false);
      deviceMapper.updateById(device);
    }
    warnEvent.setReset(true);
    // 消费消息
    warnMessageService.removeMessageByWarnId(warnEvent.getId());
    return warnEventMapper.updateById(warnEvent);
  }

  @Override
  public long updateWarnEvent(
      String moduleName, WarnEvent warnEvent, String warnType, String departmentName) {
    // 删除之前推送的消息
    warnMessageService.removeMessageByWarnId(warnEvent.getId());
    // 找到指定部门的员工的员工
    List<UserInfo> users = userInfoMapper.getUsersByDepartmentName(departmentName);
    List<Long> userInfoIds = users.stream().map(UserInfo::getId).collect(Collectors.toList());
    return updateWarnEvent(moduleName, warnEvent, warnType, userInfoIds);
  }

  @Override
  public long updateWarnEvent(
      String moduleName, WarnEvent warnEvent, String warnType, List<Long> userInfoIds) {
    Timestamp timestamp = timeFormat(System.currentTimeMillis());
    if (warnEventMapper.updateById(warnEvent) > 0) {
      // 根据userInfoId推送消息
      return sendMessageToUsers(moduleName, warnEvent, userInfoIds, timestamp);
    }
    return 0;
  }

  private long sendMessageToUsers(
      String moduleName, WarnEvent warnEvent, List<Long> userInfoIds, Timestamp timestamp) {
    if (Objects.nonNull(userInfoIds) && !userInfoIds.isEmpty()) {
      for (Long userId : userInfoIds) {
        WarnMessage warnMessage =
            new WarnMessage()
                .setReceiveUserId(userId)
                .setModuleName(moduleName)
                .setWarnEventId(warnEvent.getId())
                .setCreateTime(timestamp);
        // 发送短信
        warnMessageService.insertMessage(warnMessage);
      }
    }
    return warnEvent.getId();
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public long insertWarnEvent(
      String moduleName, WarnEvent warnEvent, String warnType, List<Long> userInfoIds) {
    Timestamp timestamp = timeFormat(System.currentTimeMillis());
    warnEvent.setType(warnType).setReset(false).setCreateTime(timestamp).setUpdateTime(timestamp);
    if (warnEventMapper.insert(warnEvent) > 0) {
      // 根据userInfoId推送消息
      return sendMessageToUsers(moduleName, warnEvent, userInfoIds, timestamp);
    }
    return 0;
  }

  /**
   * 设备数据异常,消息推送至监控中心
   *
   * @param moduleName 系统名称
   * @param warnEvent 告警案件实体
   * @param warnType 告警类型
   */
  @Override
  public long insertWarnEvent(
      String moduleName, WarnEvent warnEvent, String warnType, String departmentName) {
    // 找到指定部门的员工的员工
    List<UserInfo> users = userInfoMapper.getUsersByDepartmentName(departmentName);
    List<Long> userInfoIds = users.stream().map(UserInfo::getId).collect(Collectors.toList());
    return insertWarnEvent(moduleName, warnEvent, warnType, userInfoIds);
  }

  @Override
  public long insertWarnEvent(
      String moduleName, WarnEvent warnEvent, String warnType, Long userInfoId) {
    Timestamp timestamp = timeFormat(System.currentTimeMillis());
    warnEvent.setType(warnType).setReset(false).setCreateTime(timestamp).setUpdateTime(timestamp);
    if (warnEventMapper.insert(warnEvent) > 0) {
      // 根据userInfoId推送消息
      WarnMessage warnMessage =
          new WarnMessage()
              .setReceiveUserId(userInfoId)
              .setModuleName(moduleName)
              .setWarnEventId(warnEvent.getId())
              .setCreateTime(timestamp);
      warnMessageService.insertMessage(warnMessage);
      return warnEvent.getId();
    }
    return 0;
  }
}
